/**
 * @author		Sergey Suzdalskiy
 * @e-mail:		sergey.suzdalskiy@gmail.com
 */
package ua.kiev.gcore.assets.storage
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.DisplayObject;
	import flash.display.MovieClip;
	import flash.display.Sprite;
	import flash.events.ErrorEvent;
	import flash.events.Event;
	import flash.geom.Rectangle;
	import flash.utils.Dictionary;
	
	import ua.kiev.gcore.assets.event.AssetEvent;
	import ua.kiev.gcore.assets.loader.AssetLoader;
	import ua.kiev.gcore.logger.Logger;

	public class AssetsStorage
	{
		private static var items:Dictionary = new Dictionary();
		
		public static function addDisplayObject(asset:AssetItem, item:DisplayObject):void{
			if(asset.symbol){
				if(item.hasOwnProperty(asset.symbol)){
					items[asset.id] = item[asset.symbol];
				}else{
					Logger.ERROR("[AssetsStorage] loded item id: ", asset.id," path: ", asset.path, " hasn't property: ", asset.symbol);
				}
			}else{
				items[asset.id] = item;
			}
		}
		
		public static function getAssetItem(id:String):AssetItem{
			return AssetsItemStorage.getItem(id);
		}
		
		public static function getDisplayObject(id:String):DisplayObject{
			var result:DisplayObject;			
			if(items[id]){
				if(items[id] is Bitmap){
					result = duplicateBitmap(items[id]);
				}else{
					result = duplicateDisplayObject(items[id]);
				}					
			}			
			return result;
		}
		
		
		public static function loadDisplayObject(id:String, target:Sprite = null, mock:DisplayObject = null, error:DisplayObject = null, completeFunction:Function = null, mainFrame:String = null):Boolean{
			
			var asset:AssetItem = getAssetItem(id);
			if(!asset){
				return false
			}
			
			var loader:AssetLoader = new AssetLoader(target, mock, error, completeFunction, asset, mainFrame);
			loader.addEventListener(AssetEvent.ASSET_LOAD_COMPLETE, loadAssetComplete);
			
			loader.load(asset);	
			return true;
		}
		
		public static function sendItemToFunction(id:String, completeFunction:Function, error:DisplayObject = null):void
		{				
			var displayObject:DisplayObject = getDisplayObject(id);
			if(displayObject){
				if(completeFunction != null){
					completeFunction(displayObject);
				}
			}else{
				if(!loadDisplayObject(id,null,null,error,completeFunction)){
					if(completeFunction != null){
						completeFunction(error);
					}
				}
			}
		}
		
		public static function addItemToSprite(id:String, target:Sprite, mock:DisplayObject = null, error:DisplayObject = null, mainFrame:String = null):void
		{
			if(!target){
				return ;
			}			
			var displayObject:DisplayObject = getDisplayObject(id);
			if(displayObject){
				if((displayObject is MovieClip)&&(mainFrame)){
					(displayObject as MovieClip).gotoAndStop(mainFrame);
				}
				target.addChild(displayObject);
			}else{
				if(loadDisplayObject(id,target,mock,error,null,mainFrame)){
					if(mock){
						target.addChild(mock);
					}
				}else{
					if(error){
						target.addChild(error);
					}
				}
			}			
		}
		
		
		
		private static function loadAssetComplete(event:AssetEvent):void{
			var assetLoader:AssetLoader = event.currentTarget as AssetLoader;	
			assetLoader.removeEventListener(AssetEvent.ASSET_LOAD_COMPLETE, loadAssetComplete);
			var data:DisplayObject = assetLoader.loadData;
			if(data){
				addDisplayObject(assetLoader.asset, data);
			}
			
			if(assetLoader.completeFunction != null){
				var resultCompleteFunction:DisplayObject = getDisplayObject(assetLoader.asset.id);				
				if(resultCompleteFunction){
					assetLoader.completeFunction(resultCompleteFunction);
				}else{
					assetLoader.completeFunction(assetLoader.error)
				}
			}
			var target:Sprite = assetLoader.target;
			if(target){
				var mock:DisplayObject = assetLoader.mock;
				var error:DisplayObject = assetLoader.error;
				if((mock) && (target.contains(mock))){
					target.removeChild(mock);
				}
				var result:DisplayObject = getDisplayObject(assetLoader.asset.id);
				if(result){
					if((result is MovieClip)&&(assetLoader.mainFrame)){
						(result as MovieClip).gotoAndStop(assetLoader.mainFrame);
					}
					target.addChild(result);
				}else{
					if(error){
						target.addChild(error);
					}
				}
			}
			assetLoader.destroy();
			assetLoader = null;
		}
		
		public static function duplicateBitmap( target:Bitmap, autoAdd:Boolean = false ):Bitmap
		{
			// create duplicate
			var targetBitmapData:BitmapData = target.bitmapData;
			var duplicate:Bitmap = new Bitmap(targetBitmapData, target.pixelSnapping, target.smoothing);
			
			// duplicate properties
			duplicate.transform = target.transform;
			duplicate.filters = target.filters;
			duplicate.cacheAsBitmap = target.cacheAsBitmap;
			duplicate.opaqueBackground = target.opaqueBackground;
			if ( target.scale9Grid ) {
				var rect:Rectangle = target.scale9Grid;
				duplicate.scale9Grid = rect;
			}
			
			// add to target parent's display list
			// if autoAdd was provided as true
			if ( autoAdd && target.parent ) {
				target.parent.addChild( duplicate );
			}
			return duplicate;
		}
		
		public static function duplicateDisplayObject(target:DisplayObject):DisplayObject
		{
			// create duplicate
			var targetClass:Class = Object(target).constructor;
			var duplicate:Object;
			try{
				duplicate = new targetClass();
			}catch(error:Error){
				trace("[duplicateDisplayObject] error: " + error.message);
				return null;
			}
			
			// duplicate properties
			duplicate.transform = target.transform;
			duplicate.filters = target.filters;
			duplicate.cacheAsBitmap = target.cacheAsBitmap;
			duplicate.opaqueBackground = target.opaqueBackground;
			if ( target.scale9Grid ) {
				var rect:Rectangle = target.scale9Grid;
				duplicate.scale9Grid = rect;
			}
						
			return duplicate as DisplayObject;
		}
	}
}